<?php
/**
 * @Description 图片处理类 
 * @Author yulipu
 * @Time 2012-3-22
 * 可能有bug 没有那么严格测试过
 * 用法
 *  include "image.class.php";
 *  $image = new YImage('./');
 *  echo $image->thumb('b.jpg', 400, 400, 'thumb_');  等比例缩放图片 返回新图片名
 *  echo $image->cut('a.jpg', 500, 500); 自动裁剪图片
 *  echo $image->cut('a.jpg', 500,500, false, array(50,50), 'cut1_');  费等比例裁剪图片 返回新图片名
 *  echo $image->waterMark('ground.jpg', 'water.gif'); 为图片加水印图片 返回新图片名
 *
 */
class YImage {
	private $imgPath = '';  //待处理图片所在的目录
	private $oldImgHandler = null;  //待处理图片的资源
	private $newimgHandler = null;  //处理后后新图片的资源
	private $groundImgHandler = null;
	private $waterImgHandler = null;
 
	/**
	* 初始化待缩略图片的目录路径
	*/
	function __construct($imgPath) {
		$this->imgPath = rtrim($imgPath, '/').'/';
	}
	/**
	* 缩放图片的入口方法
	* @param $imgName 待缩放图片的名字
	* @param $width 缩放后想要的宽度 实际要 <= 这个大小 因为是等比例缩放
	* @param $height 缩放后想要的高度 实际要 <= 这个大小 因为是等比例缩放
	* @param $prefix 缩放后图片名的前缀
	*/
	function thumb($imgName, $width, $height, $prefix='tb_') {
		if(file_exists($this->imgPath.$imgName)) {
			//获取待处理图片信息数组 包含大小类型信息
			$thumb_imgInfo = $this->getImgInfo($imgName);
			//获取待处理图片(imgName)资源
			$this->oldImgHandler = $this->getImgSource($imgName, $thumb_imgInfo);
			//计算图片缩放后的大小
			$newSize = $this->getNewSize($imgName, $width, $height, $thumb_imgInfo);
			//获取新的图片资源,处理gif透明处背景理问题,关闭旧资源
			$this->newimgHandler = $this->prepareImage($newSize, $this->oldImgHandler, $thumb_imgInfo);
			//保存图片并把缩放后的图片名返回,关闭新图片资源
			return $this->createNewImage($this->newimgHandler, $thumb_imgInfo, $prefix.$imgName);
		}
		die($imgName.'不存在');
	}
	/**
	* 非等比例切割图片
	* @param $imgName 待处理的图片名
	* @param $width 要切割的宽度
	* @param $height 要切割的高度
	* @param $auto 是否自动切割
	* @param $cutPos 当且仅当指定为手动切割时需要传入$pos来指定开始切割的坐标
	*
	*/
	function cut($imgName, $width, $height, $auto=true, $startPos=array(0,0), $prefix='cut_') {
		if(file_exists($this->imgPath.$imgName)) {
			//取得要切割图片的信息
			$cut_imageInfo = $this->getImgInfo($imgName);
			//计算出切割位置posX posY
			$cutPos = $this->cutPosition($cut_imageInfo, $width, $height, $auto, $startPos);
			//准备一张图片,以便把原图片的一部分拷贝进来
			$this->newImgHandler = imagecreatetruecolor($width, $height);
			//打开待处理的图片资源,准备切割
			$this->oldImgHandler = $this->getImgSource($imgName, $cut_imageInfo);
			//开始拷贝
			$this->copyImage1($this->newImgHandler, $this->oldImgHandler, array('posX'=>0,'posY'=>0), $cutPos, array('width'=>$width, 'height'=>$height));
			//保存图片并把缩放后的图片名返回
			return $this->createNewImage($this->newImgHandler, $cut_imageInfo, $prefix.$imgName);
		}
		die($imgName.'不存在');
	}
	/**
	* 为图片加水印图片的入口方法
	* @param $groundImgName 要加水印的图片名
	* @param $waterImgName 水印图片名
	* @param $waterPos 水印图片位置
	* 0 -- 随机位置<br />
	* 1 -- 顶端左侧  2 -- 顶端居中  3 -- 顶端右侧<br />
	* 4 -- 中间左侧  5 -- 中间居中  6 -- 中间右侧<br />
	* 7 -- 底部左侧  8 -- 底部居中  9-- 底部右侧<br />
	* @param $prefix 加水印后图片的前缀名
	* @return 处理后图片的名字
	*/
	function waterMark($groundImgName, $waterImgName, $waterPos = 9, $prefix = 'wa_') {
		if(file_exists($this->imgPath.$groundImgName) && file_exists($this->imgPath.$waterImgName)) {
			$groundImgInfo = $this->getImgInfo($groundImgName);
			$waterImgInfo = $this->getImgInfo($waterImgName);
			//确定水印位置
			$pos = $this->waterPosition($groundImgInfo, $waterImgInfo, $waterPos);
			if(false === $pos) die('水印图片太大,无法完成操作');
			//得到图片资源
			$this->groundImgHandler = $this->getImgSource($groundImgName, $groundImgInfo);
			$this->waterImgHandler = $this->getImgSource($waterImgName, $waterImgInfo);
			//把水印图片拷贝到背景图片上,并关闭水印图片资源
			if( $this->copyImage($this->groundImgHandler, $this->waterImgHandler, $pos, $waterImgInfo) ) {
				//生成新图片并保存到旧图片所在的路径,关闭背景图片资源
				return $this->createNewImage($this->groundImgHandler, $groundImgInfo, $prefix.$groundImgName);
			}
		}
		die('所需的图片不存在');
	}
	/**
	* 得到图片的相关信息
	* @param $imgName 待处理图片的名字
	* @return 返回数组,包含了待处理图片的相关信息
	*/
	private function getImgInfo($imgName) {
		$imgInfo = array();
		$tempInfo = getimagesize($this->imgPath.$imgName);
		$imgInfo['width'] = $tempInfo[0];
		$imgInfo['height'] = $tempInfo[1];
		$imgInfo['type'] = $tempInfo[2];
		return $imgInfo;
	}
	/**
	* 取得要处理的图像的资源
	* @param $imgInfo 待处理图片的信息数组
	* @param $imgName 待处理图片名字
	* @return 待处理图片的资源
	*/
	private function getImgSource($imgName, & $imgInfo) {
		$srcImg = $this->imgPath.$imgName;
		$imgHandler = null;
		switch($imgInfo['type']) {
			case 1:  //gif
				$imgHandler = imagecreatefromgif($srcImg);  //打开图片得到资源
				break;
			case 2:  //jpg
				$imgHandler = imagecreatefromjpeg($srcImg);
				break;
			case 3:  //png
				$imgHandler = imagecreatefrompng($srcImg);
				break;
			default:
				return null;
		}
		return $imgHandler;
	}
	/**
	* 计算等比例缩放后图片的大小
	* @param $imgName 待缩放图片的名字
	* @param $width 要缩放成的宽度
	* @param $height 要缩放成的高度
	* @param $imgInfo
	* @return 返回包含新图片大小的数组
	*/
	private function getNewSize($imgName, $width, $height, & $imgInfo) {
		$newSize = array(
			'width' => $imgInfo['width'],
			'height' => $imgInfo['height']
		);
		//宽度比原图小时才有效,否则就用原来大小
		if($width < $imgInfo['width']) {
			$newSize['width'] = $width;
		}
		if($height < $imgInfo['height']) {
			$newSize['height'] = $height;
		}
		//图片等比例缩放算法
		if($imgInfo['width'] * $newSize['width'] > $imgInfo['height'] * $newSize['height']) {
			$newSize['height'] = round($imgInfo['height'] * $newSize['width'] / $imgInfo['width']);
		} else {
			$newSize[width] = round($imgInfo['width'] * $newSize['height'] / $imgInfo['height']);
		}
		return $newSize;
	}
	/**
	* 创建缩略后新图片资源,并关闭旧资源
	* @param $size 数组 包含了新图片大小
	* @param $imgHandler 
	* @param $imgInfo 图片信息
	* Method imagecolortransparent() 有第二个参数时是将某颜色定义为透明色 没有第二个参数时是返回当前透明色的标识符<br />
	* Method imagecolorstotal() 取得图像的调色板中颜色的数目<br />
	* Method imagecolorsforindex() 取得索引对应的颜色<br />
	* Method imagecolorallocate() 准备颜色<br />
	* @return 新图片资源
	*/
	private function prepareImage($size, $imgHandler, & $imgInfo) {
		$hanlder = imagecreatetruecolor($size['width'], $size['height']);  //创建一张图片资源
		$opacityFlag = imagecolortransparent($imgHandler);  //返回当前透明色的标识符 int型
		if($opacityFlag >= 0 && $opacityFlag <= imagecolorstotal($imgHandler)) {
			$transColor = imagecolorsforindex($imgHandler, $opacityFlag);  //取得索引对应的颜色
			$newColor = imagecolorallocate($hanlder, $transColor['red'], $transColor['green'], $transColor['blue']);  //准备颜色
			imagefill($hanlder, 0, 0, $newColor);  //用颜色填充新图片
			imagecolortransparent($hanlder, $newColor);  //有第二个参数,是将某颜色定义为透明色
		}
		//把旧图片复制到新图片上
		imagecopyresized($hanlder, $imgHandler, 0, 0, 0, 0, $size['width'], $size['height'], 
		$imgInfo['width'], $imgInfo['height']);  
		imagedestroy($imgHandler);  //释放旧图片的资源
		return $hanlder;  //返回新图片资源
	}
	/**
	* 生成新图片并保存到旧图片所在的路径,关闭新图片资源
	* @param $imgHandler 
	* @param $imgInfo
	* @param $newName 新图片的名字(包含前缀)
	* @return 新图片名字
	*/
	private function createNewImage($imgHandler, & $imgInfo, $newName) {
		switch($imgInfo['type']) {
		case 1 :  //gif
			imagegif($imgHandler, $this->imgPath.$newName);  //生成新图片并保存到旧图片所在的路径
			break;
		case 2 :  //jpg
			imagejpeg($imgHandler, $this->imgPath.$newName);
			break;
		case 3 :  //png
			imagepng($imgHandler, $this->imgPath.$newName);
			break;
		}
		imagedestroy($imgHandler);  //销毁新图片资源
		return $newName;
	}
	/**
	* 计算出切割位置
	*
	*/
	private function cutPosition(& $srcImgInfo, $width, $height, $auto=true, $startPos=array(0,0)) {
		$pos = array();
		if(true === $auto) {
			$pos['posX'] = round( ($srcImgInfo['width']-$width) / 2 );
			$pos['posY'] = round( ($srcImgInfo['height']-$height) /2 );;
		} else {
			$pos['posX'] = $startPos[0];
			$pos['posY'] = $startPos[1];
		}
		return $pos;
	}
	/**
	* 计算水印的位置
	*/
	private function waterPosition(& $groundImgInfo, & $waterImgInfo, $waterPos=9) {
		if( ($groundImgInfo['width'] < $waterImgInfo['width']) || ($groundImgInfo['height'] < $waterImgInfo['width']) ) {
			return false;
		} 
		$posX = $groundImgInfo['width'] - $waterImgInfo['width'];
		$posY = $groundImgInfo['height'] - $waterImgInfo['height'];
		switch($waterPos) {
			case 1:
				$posX = 0;
				$posY = 0;
				break;
			case 2:
				$posX = round( ($groundImgInfo['width'] - $waterImgInfo['width']) / 2 );
				$posY = 0;
				break;
			case 3:
				$posX = $groundImgInfo['width'] - $waterImgInfo['width'];
				$posY = 0;
				break;
			case 4:
				$posX = 0;
				$posY = round( ($groundImgInfo['height'] - $waterImgInfo['height']) / 2 );
				break;
			case 5:
				$posX = round( ($groundImgInfo['width'] - $waterImgInfo['width']) / 2 );
				$posY = round( ($groundImgInfo['height'] - $waterImgInfo['height']) / 2 );
				break;
			case 6:
				$posX = $groundImgInfo['width'] - $waterImgInfo['width'];
				$posY = round( ($groundImgInfo['height'] - $waterImgInfo['height']) / 2 );
				break;
			case 7:
				$posX = 0;
				$posY = $groundImgInfo['height'] - $waterImgInfo['height'];
				break;
			case 8:
				$posX = round( ($groundImgInfo['width'] - $waterImgInfo['width']) / 2 );
				$posY = $groundImgInfo['height'] - $waterImgInfo['height'];
				break;
			case 9:
				//$posX = $groundImgInfo['width'] - $waterImgInfo['width'];
				//$posY = $groundImgInfo['height'] - $waterImgInfo['height'];
				break;
			case 0:
			default:
				$posX = mt_rand(0, $groundImgInfo['width']-$waterImgInfo['width']);
				$posY = mt_rand(0, $groundImgInfo['height']-$waterImgInfo['height']);
				break;
		}
		return array('posX'=>$posX, 'posY'=>$posY);
	}
	/**
	* 把原图片拷贝到目标图片上,销毁原图片资源
	*
	*/
	private function copyImage($dst_imgHandler, $src_imghandler, $pos, & $size) {
		$flag = imagecopy($dst_imgHandler, $src_imghandler, $pos['posX'], $pos['posY'], 0, 0, $size['width'], $size['height']);
		imagedestroy($src_imghandler);
		if($flag)
			return true;
		return false;
	} 
	private function copyImage1($dst_imgHandler, $src_imghandler, $dstPos, $srcPos, $size) {
		$flag = imagecopy($dst_imgHandler, $src_imghandler, $dstPos['posX'], $dstPos['posY'], 
		$srcPos['posX'], $srcPos['posY'], $size['width'], $size['height']);
		imagedestroy($src_imghandler);
		if($flag)
			return true;
		return false;
	}
	/**
	* 析构函数
	*/
	function __destruct() {
		if(is_resource($this->oldImgHandler)) {
			imagedestroy($this->oldImgHandler);
		}
		if(is_resource($this->newimgHandler)) {
			imagedestroy($this->newimgHandler);
		}
		if(is_resource($this->groundImgHandler)) {
			imagedestroy($this->groundImgHandler);
		}
		if(is_resource($this->waterImgHandler)) {
			imagedestroy($this->waterImgHandler);
		}
    }
 
}